'use client'

import { useEffect, useRef } from 'react'

export default function FXCanvas({ effect = 'constellations' }: { effect?: 'constellations' | 'comets' | 'grid' }) {
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const dprMax = 2
    const IS_MOBILE = window.matchMedia('(max-width: 820px)').matches

    // ===== 创建 Canvas =====
    function makeCanvas(el: HTMLElement) {
      const c = document.createElement('canvas')
      c.style.position = 'absolute'
      c.style.inset = '0'
      c.style.display = 'block'
      el.appendChild(c)
      const ctx = c.getContext('2d', { alpha: true })!
      return { el, c, ctx, dpr: 1, raf: 0, playing: false, t: 0, items: [] as any[] }
    }

    // ===== Resize =====
    function resizeFx(fx: any) {
      const r = fx.el.getBoundingClientRect()
      fx.dpr = Math.min(window.devicePixelRatio || 1, dprMax)
      fx.c.width = Math.max(1, Math.round(r.width * fx.dpr))
      fx.c.height = Math.max(1, Math.round(r.height * fx.dpr))
    }

    // ===== 所有效果定义 =====
    const effects = {
      constellations: {
        init(fx: any) {
          fx.items = Array.from({ length: 120 }, () => ({
            x: Math.random(),
            y: Math.random(),
            s: 1.2 + Math.random() * 2.6,
            tw: Math.random() * Math.PI * 2
          }))
        },
        draw(fx: any, t: number) {
          const { ctx, c, items, dpr } = fx
          const w = c.width,
            h = c.height
          ctx.clearRect(0, 0, w, h)
          const neb = ctx.createRadialGradient(w * 0.2, h * 0.1, 0, w * 0.2, h * 0.1, Math.max(w, h) * 0.8)
          neb.addColorStop(0, 'rgba(124,92,255,0.05)')
          neb.addColorStop(1, 'rgba(124,92,255,0.00)')
          ctx.fillStyle = neb
          ctx.fillRect(0, 0, w, h)

          for (const p of items) {
            const tw = IS_MOBILE ? 0.5 : 0.5 + 0.5 * Math.sin(t * 0.002 + p.tw)
            ctx.fillStyle = `rgba(220,230,255,${0.14 + tw * 0.14})`
            const r = p.s * dpr
            ctx.beginPath()
            ctx.arc(p.x * w, p.y * h, r, 0, Math.PI * 2)
            ctx.fill()

            ctx.strokeStyle = `rgba(124,92,255,${0.1 + tw * 0.08})`
            ctx.lineWidth = 1 * dpr
            ctx.lineCap = 'round'
            ctx.beginPath()
            ctx.moveTo(p.x * w - 2.2 * dpr, p.y * h)
            ctx.lineTo(p.x * w + 2.2 * dpr, p.y * h)
            ctx.moveTo(p.x * w, p.y * h - 2.2 * dpr)
            ctx.lineTo(p.x * w, p.y * h + 2.2 * dpr)
            ctx.stroke()
          }
        }
      },
      comets: {
        init(fx: any) {
          fx.items = Array.from({ length: 9 }, () => ({
            y: Math.random(),
            life: Math.random() * 4000 + 3500,
            t0: performance.now() - Math.random() * 3000
          }))
        },
        draw(fx: any, t: number) {
          const { ctx, c, items, dpr } = fx
          const w = c.width,
            h = c.height
          ctx.clearRect(0, 0, w, h)
          const ang = -Math.PI / 6,
            sin = Math.sin(ang),
            cos = Math.cos(ang)
          const extra = Math.max(w, h) * 1.2
          ctx.lineCap = 'round'
          for (const s of items) {
            const dt = IS_MOBILE ? 0 : (t - s.t0) % s.life
            const prog = 1 - dt / s.life
            const pathLen = w + extra * 2
            const head = prog * pathLen + -extra
            const tailLen = 380 * dpr
            const x2 = head,
              y2 = s.y * h
            const x1 = head - tailLen,
              y1 = s.y * h
            const rx1 = x1 * cos - y1 * sin,
              ry1 = x1 * sin + y1 * cos
            const rx2 = x2 * cos - y2 * sin,
              ry2 = x2 * sin + y2 * cos
            const g = ctx.createLinearGradient(rx1, ry1, rx2, ry2)
            g.addColorStop(0, 'rgba(180,200,255,0.00)')
            g.addColorStop(0.5, 'rgba(200,210,255,0.12)')
            g.addColorStop(1, 'rgba(180,200,255,0.00)')
            ctx.strokeStyle = g
            ctx.lineWidth = 1.25 * dpr
            ctx.beginPath()
            ctx.moveTo(rx1, ry1)
            ctx.lineTo(rx2, ry2)
            ctx.stroke()
          }
        }
      },
      grid: {
        init() {},
        draw(fx: any, t: number) {
          const { ctx, c, dpr } = fx
          const w = c.width,
            h = c.height
          ctx.clearRect(0, 0, w, h)
          const gap = 64 * dpr,
            drift = IS_MOBILE ? 0 : Math.sin(t * 0.0008) * 2 * dpr
          ctx.strokeStyle = 'rgba(190,200,255,0.08)'
          ctx.lineWidth = 1 * dpr
          ctx.beginPath()
          for (let x = drift % gap; x < w; x += gap) {
            ctx.moveTo(x, 0)
            ctx.lineTo(x, h)
          }
          for (let y = drift % gap; y < h; y += gap) {
            ctx.moveTo(0, y)
            ctx.lineTo(w, y)
          }
          ctx.stroke()

          ctx.strokeStyle = 'rgba(124,92,255,0.11)'
          ctx.beginPath()
          ctx.moveTo(0, h * 0.55)
          ctx.lineTo(w, h * 0.55)
          ctx.stroke()

          const sweepX = IS_MOBILE ? w * 0.35 : ((t * 0.05) % (w + 200 * dpr)) - 100 * dpr
          const g = ctx.createRadialGradient(sweepX, h * 0.4, 0, sweepX, h * 0.4, 220 * dpr)
          g.addColorStop(0, 'rgba(34,211,238,0.06)')
          g.addColorStop(1, 'rgba(34,211,238,0.00)')
          ctx.fillStyle = g
          ctx.fillRect(0, 0, w, h)
        }
      }
    }

    const el = containerRef.current
    if (!el) return
    const e = effects[effect]
    if (!e) return
    const fx = makeCanvas(el)
    resizeFx(fx)
    e.init(fx)

    if (IS_MOBILE) {
      e.draw(fx, 0)
      const resizeObserver = new ResizeObserver(() => {
        resizeFx(fx)
        e.draw(fx, 0)
      })
      resizeObserver.observe(el)
      return
    }

    function loop(now: number) {
      if (!fx.playing) return
      fx.t = now || 0
      e.draw(fx, fx.t)
      fx.raf = requestAnimationFrame(loop)
    }

    fx.playing = true
    cancelAnimationFrame(fx.raf)
    loop()

    const io = new IntersectionObserver(
      (ents) => {
        for (const entry of ents) {
          if (entry.target !== el) continue
          if (entry.isIntersecting) {
            resizeFx(fx)
            e.init(fx)
            fx.playing = true
            cancelAnimationFrame(fx.raf)
            loop()
          } else {
            fx.playing = false
            cancelAnimationFrame(fx.raf)
          }
        }
      },
      { threshold: 0, rootMargin: '700px 0px 700px 0px' }
    )
    io.observe(el)

    const resizeObserver = new ResizeObserver(() => {
      if (fx.playing) resizeFx(fx)
    })
    resizeObserver.observe(el)

    const onResize = () => {
      if (fx.playing) resizeFx(fx)
    }
    window.addEventListener('resize', onResize, { passive: true })

    return () => {
      fx.playing = false
      cancelAnimationFrame(fx.raf)
      io.disconnect()
      resizeObserver.disconnect()
      window.removeEventListener('resize', onResize)
    }
  }, [effect])

  return <div ref={containerRef} className="fx relative w-full h-[500px] bg-[#050505] overflow-hidden" />
}
